#include "sudoku_board.h"
//------------------------------------------------------------------------------------------------------------
void SudokuBoard::init()
{
    cout << "[ENTER]\tSudokuBoard::init\n";

    srand(time(NULL));

    SudokuField* f;
    vector<int>* availableValues;

    //tworzenie pól oraz ich inicjalizacja
    BOOST_FOREACH(int idx, *(sudDef->getPossibleIndices()))
    {
        //cout << "idx=" << idx << " ";

        if((initialSudoku)[idx] != 0)
        {
            availableValues = new vector<int>();
            availableValues->push_back((initialSudoku)[idx]);
        }
        else
        {
            availableValues = sudDef->getGeneralPossibleValues(); //new set<int>(sudDef->getGeneralPossibleValues()->begin(), sudDef->getGeneralPossibleValues()->end());
        }

        //cout << "avls[" << idx << "]: " << availableValues->size() << " (";
        BOOST_FOREACH(int idx, *(availableValues))
        {
            //cout << idx << " ";
        }
        //cout << ")" << endl;

        sudokuBoard.insert(std::pair<int,SudokuField*>(idx, new SudokuFieldOrder(idx, availableValues)));

    }
    cout << endl;

    //inicjalizacja mapy groupsByField
    sudDef->getGroupsByField(&groupsByField);

    //update all fields

    BOOST_FOREACH(int idx, *(sudDef->getPossibleIndices()))
    {
        updateAvailableSet(sudokuBoard[idx]);
        //sudokuBoard[idx]->print();
    }

	laps = 0;

    cout << "[EXIT]\tSudokuBoard::init\n";
}
//------------------------------------------------------------------------------------------------------------
SudokuBoard::SudokuBoard(SudokuSolvingAlgorithm* pSudAlgo, SudokuDefinition* pSudDef, char* fileName)
{
    cout << "[ENTER]\tSudokuBoard::SudokuBoard\n";

    sudAlgo = pSudAlgo;
    sudDef = pSudDef;
    this->fileName = fileName;
    fetchSudokuInit();
    init();

    cout << "[EXIT]\tSudokuBoard::SudokuBoard\n";
}
//------------------------------------------------------------------------------------------------------------
SudokuBoard::SudokuBoard(SudokuSolvingAlgorithm* pSudAlgo, SudokuDefinition* pSudDef, std::map<int,int>* initialSudoku)
{
    cout << "[ENTER]\tSudokuBoard::SudokuBoard\n";

    sudAlgo = pSudAlgo;
    sudDef = pSudDef;
    this->initialSudoku = *initialSudoku; //copying map
    init();
    cout << "[EXIT]\tSudokuBoard::SudokuBoard\n";
}
//------------------------------------------------------------------------------------------------------------
void SudokuBoard::updateAvailableSet(SudokuField* f)
{
	//cout << "[ENTER]\tSudokuBoard::updateAvailableSet\n";
    //SudokuField* f = fit->second;
    if(f->getAvailableValues()->size() == 1 && *(f->value) != 0)
    {
    	//cout << "[EXIT]\tSudokuBoard::updateAvailableSet availableSet size is 1\n";
        return; //if field is final and different than 0, then exit
    }

    //copy from possible set to available set
    f->initAvailableSet();

    //cout << "------------\n";
	BOOST_FOREACH(Group* g, *(groupsByField[f->getId()]))
	{
		g->updateAvailableSet(f->getAvailableValues(), &sudokuBoard, 0);

/*
		BOOST_FOREACH(int idx, *(g->getIndicesVector()))
		{
		    int v = *(sudokuBoard[idx]->value);                              //get value of field with index idx
            unordered_set<int>::iterator ait = f->getAvailableValues()->find(v);      //set iterator on element with value==v
            if(ait != f->getAvailableValues()->end() && v != 0)
            {
                //cout << "v["<< idx<<"]=" << v << " ait=" << *ait << endl;
                f->getAvailableValues()->erase(ait);                            //remove element with value==v from available set
            }
		}
        //cout << "------------\n";
*/
	}
	//cout << "[EXIT]\tSudokuBoard::updateAvailableSet\n";
}
//------------------------------------------------------------------------------------------------------------
void SudokuBoard::snapshot()
{
    //cout << "[ENTER] SudokuBoard::snapshot";
    map<int, int>* solution = new map<int, int>();
    BOOST_FOREACH(int idx, *(sudDef->getPossibleIndices()))
    {
        solution->insert(std::pair<int,int>(idx, *(sudokuBoard[idx]->value)));
    }
    solutions.push_back(solution);
    //cout << "[EXIT] SudokuBoard::snapshot";
}
//------------------------------------------------------------------------------------------------------------
void SudokuBoard::print()
{
    //cout << "[ENTER]\tSudokuBoard::print\n";
    cout << "PRINT SUDOKU BOARD:\nboard size: " << sudokuBoard.size() << endl;
    cout << "availableValues: ";

    BOOST_FOREACH(int v, *(sudDef->getGeneralPossibleValues()))
    {
        cout << " " << v;
    }
    cout << endl;

    BOOST_FOREACH(int_sf_pair pf, sudokuBoard)
    {
        //pf.second->print();
    }

    //cout << "[EXIT]\tSudokuBoard::print\n";
}
//------------------------------------------------------------------------------------------------------------
void SudokuBoard::startSolving(int maxSol)
{
	cout << "[ENTER]\t ------------------------- SudokuBoard::startSolving -------------------------\n";

    this->maxSol = maxSol;
	vector<int>::iterator it = sudDef->getPossibleIndices()->begin();
	vector<int>::iterator end = sudDef->getPossibleIndices()->end();

	sudAlgo->solve(this, it, &end);

    //print();
	cout << "---------------------------------------------------\nALGORITHM LAPS (SudokuBoard::startSolving): " << laps << endl;
    cout << "[EXIT]\tSudokuBoard::startSolving\n";
}
//------------------------------------------------------------------------------------------------------------
 void SudokuBoard::fetchSudokuInit()
 {
    cout << "[ENTER]SudokuBoard::fetchSudokuInit\n";

    int idx, v;
    ifstream read(fileName);

    //relFile.open(fileName, ios::in);
    //if(!relFile)
      //  return -1;
    //cout << "Starting of fetching of file " << fileName << endl;
    //fetching size
    //read >> size;
    //cout << "size=" << size << endl;
    //fetching indices
    //cout << "indices: ";
    //BOOST_FOREACH(idx, *(sudDef->getPossibleIndices()))
    for(idx = 1; idx < sudDef->getPossibleIndices()->size(); idx++)
    {
        read >> v;
        cout << "f[" << idx << "]=" << v << " ";
        initialSudoku[idx] = v;
    }
    cout << endl;

    cout << "[EXIT]SudokuBoard::fetchSudokuInit\n";
 }
 //------------------------------------------------------------------------------------------------------------
